//*****************************************************************************
//
// Lab5.c - user programs, File system, stream data onto disk
// Jonathan Valvano, March 16, 2011, EE345M
//     You may implement Lab 5 without the oLED display
//*****************************************************************************
// PF1/IDX1 is user input select switch
// PE1/PWM5 is user input down switch 
#include <stdio.h>
#include <string.h>
#include "inc/hw_types.h"
#include "Interpreter.h"
#include "adc.h"
#include "os.h"
#include "lm3s8962.h"
#include "edisk.h"
#include "efile.h"

void printLab(unsigned char *pucBuffer, unsigned long ulCount);


unsigned long NumCreated;   // number of foreground threads created
unsigned long NumSamples;   // incremented every sample
unsigned long DataLost;     // data sent by Producer, but not received by Consumer

int Running;                // true while robot is running
int Making;

unsigned char MessageBuffer[512];
int MessageLength;

#define TIMESLICE 2*TIME_1MS  // thread switch time in system time units

#define LF                10
#define CR                13

#define GPIO_PF0  (*((volatile unsigned long *)0x40025004))
#define GPIO_PF1  (*((volatile unsigned long *)0x40025008))
#define GPIO_PF2  (*((volatile unsigned long *)0x40025010))
#define GPIO_PF3  (*((volatile unsigned long *)0x40025020))
#define GPIO_PG1  (*((volatile unsigned long *)0x40026008))
// PF1/IDX1 is user input select switch
// PE1/PWM5 is user input down switch 
// PF0/PWM0 is debugging output on Systick
// PF2/LED1 is debugging output 
// PF3/LED0 is debugging output 
// PG1/PWM1 is debugging output



//******** Robot *************** 
// foreground thread, accepts data from producer
// inputs:  none
// outputs: none
void Robot(void){   
unsigned long data;      // ADC sample, 0 to 1023
unsigned long voltage;   // in mV,      0 to 3000
unsigned long time;      // in 10msec,  0 to 1000 
unsigned long t=0;
unsigned char name[10];
static  unsigned long number = 0;
  OS_ClearMsTime();    
  DataLost = 0;          // new run with no lost data 
  //MessageLength = sprintf(MessageBuffer,"Robot running...");
  //printLab(MessageBuffer, MessageLength);
  sprintf(name, "Robo%d", number++);
  eFile_RedirectToFile(name);
  MessageLength = sprintf(MessageBuffer,"time(sec)\tdata(volts)\n\r");
  printLab(MessageBuffer, MessageLength);
  data = 0;
  do{
    t++;
    time=OS_MsTime();            // 10ms resolution in this OS
    //data = OS_Fifo_Get();        // 1000 Hz sampling get from producer
    voltage = (300*data)/1024;   // in mV
    MessageLength = sprintf(MessageBuffer,"%0u.%02u\t%0u.%03u\n\r",time/100,time%100,voltage/1000,voltage%1000);
	//printLab(MessageBuffer,MessageLength);
  }
  while(time < 5000);       // change this to mean 10 seconds
  eFile_EndRedirectToFile();
  MessageLength=sprintf(MessageBuffer,"done.\n\r");
  printLab(MessageBuffer,MessageLength);
  Running = 0;                // robot no longer running
  OS_Kill();
}

//************MakeFile*************
char test2[] = "abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefghij0123456789abcdefgh";
void MakeFile(void){
  int i;

  // Create and Open File
  if(eFile_Create("test")){
  	Making = 0;
	OS_Kill();
  }
  eFile_WOpen("test");
  
  // Write to it
  i=0;
  do{
    eFile_Write(test2[i]);
  }while(test2[i++] != NULL);
  
  //Close and end thread
  eFile_WClose();
  Making = 0;
  OS_Kill();
}
  
//************ButtonPush*************
// Called when Select Button pushed
// background threads execute once and return
void ButtonPush(void){
  if(Running==0){
    Running = 1;  // prevents you from starting two robot threads
    NumCreated += OS_AddThread(&Robot,1024,1);  // start a 20 second run
  }
}
//************DownPush*************
// Called when Down Button pushed
// background threads execute once and return
void DownPush(void){
  if(Making==0){
	Making = 1;
	NumCreated != OS_AddThread(&MakeFile,1024,1);
  }
}



//******** Producer *************** 
// The Producer in this lab will be called from your ADC ISR
// A timer runs at 1 kHz, started by your ADC_Collect
// The timer triggers the ADC, creating the 1 kHz sampling
// Your ADC ISR runs when ADC data is ready
// Your ADC ISR calls this function with a 10-bit sample 
// sends data to the Robot, runs periodically at 1 kHz
// inputs:  none
// outputs: none
void Producer(unsigned short data){  
  if(Running){
    if(OS_Fifo_Put(data)){     // send to Robot
      NumSamples++;
    } else{ 
      DataLost++;
    } 
  }
}
 
//******** IdleTask  *************** 
// foreground thread, runs when no other work needed
// never blocks, never sleeps, never dies
// inputs:  none
// outputs: none
unsigned long Idlecount=0;
void IdleTask(void){ 
  while(1) { 
    Idlecount++;        // debugging 
  }
}


//******** Interpreter **************
// your intepreter from Lab 4 
// foreground thread, accepts input from serial port, outputs to serial port
// inputs:  none
// outputs: none
extern void Interpreter(void); 
// add the following commands, remove commands that do not make sense anymore
// 1) format 
// 2) directory 
// 3) print file
// 4) delete file
// execute   eFile_Init();  after periodic interrupts have started

//*******************lab 5 main **********
int realmain(void){        // lab 5 real main
  OS_Init();           // initialize, disable interrupts
  Running = 0;         // robot not running
  DataLost = 0;        // lost data between producer and consumer
  NumSamples = 0;

//********initialize communication channels
  OS_Fifo_Init(512);    // ***note*** 4 is not big enough*****
  ADC_Collect(0, 1000, &Producer, 0); // start ADC sampling, channel 0, 1000 Hz
  UART_Init();

//*******attach background tasks***********
  OS_AddButtonTask(&ButtonPush,2);
  OS_AddButtonTask(&DownPush,2);
  OS_AddPeriodicThread(disk_timerproc,10*TIME_1MS,5);

  NumCreated = 0 ;
// create initial foreground threads
  NumCreated += OS_AddThread(&Interpreter,128,2); 
  NumCreated += OS_AddThread(&IdleTask,128,7);  // runs when nothing useful to do
 
  OS_Launch(TIMESLICE); // doesn't return, interrupts enabled in here
  return 0;             // this never executes
}

/*
//*****************test programs*************************
unsigned char buffer[512];
#define MAXBLOCKS 100
void diskError(char* errtype, unsigned long n){
  // printf(errtype);
  // printf(" disk error %u",n);
  OS_Kill();
}
void TestDisk(void){  DSTATUS result;  unsigned short block;  int i; unsigned long n;
  // simple test of eDisk
  // printf("\n\rEE345M/EE380L, Lab 5 eDisk test\n\r");
  result = eDisk_Init(0);  // initialize disk
  if(result) diskError("eDisk_Init",result);
  // printf("Writing blocks\n\r");
  n = 1;    // seed
  for(block = 0; block < MAXBLOCKS; block++){
    for(i=0;i<512;i++){
      n = (16807*n)%2147483647; // pseudo random sequence
      buffer[i] = 0xFF&n;        
    }
    GPIO_PF3 = 0x08;     // PF3 high for 100 block writes
    if(eDisk_WriteBlock(buffer,block))diskError("eDisk_WriteBlock",block); // save to disk
    GPIO_PF3 = 0x00;     
  }  
  // printf("Reading blocks\n\r");
  n = 1;  // reseed, start over to get the same sequence
  for(block = 0; block < MAXBLOCKS; block++){
    GPIO_PF2 = 0x04;     // PF2 high for one block read
    if(eDisk_ReadBlock(buffer,block))diskError("eDisk_ReadBlock",block); // read from disk
    GPIO_PF2 = 0x00;
    for(i=0;i<512;i++){
      n = (16807*n)%2147483647; // pseudo random sequence
      if(buffer[i] != (0xFF&n)){
        // printf("Read data not correct, block=%u, i=%u, expected %u, read %u\n\r",block,i,(0xFF&n),buffer[i]);
        OS_Kill();
      }      
    }
  }  
  // printf("Successful test of %u blocks\n\r",MAXBLOCKS);
  OS_Kill();
}
void RunTest(void){
  NumCreated += OS_AddThread(&TestDisk,128,1);  
}
//******************* test main1 **********
// SYSTICK interrupts, period established by OS_Launch
// Timer interrupts, period established by first call to OS_AddPeriodicThread
int testmain1(void){   // testmain1
  OS_Init();           // initialize, disable interrupts

//*******attach background tasks***********
  OS_AddPeriodicThread(&disk_timerproc,10*TIME_1MS,0);   // time out routines for disk
  OS_AddButtonTask(&RunTest,2);
  
  NumCreated = 0 ;
// create initial foreground threads
  NumCreated += OS_AddThread(&TestDisk,128,1);  
  NumCreated += OS_AddThread(&IdleTask,128,3); 
 
  OS_Launch(10*TIME_1MS); // doesn't return, interrupts enabled in here
  return 0;               // this never executes
}
*/
unsigned char testBuf[512];
int bufLen;
void TestFile(void){   int i; char data; 
  bufLen = sprintf(testBuf,"\n\rEE345M/EE380L, Lab 5 eFile test\n\r");
  UARTSend(testBuf, bufLen);
  // simple test of eFile
  if(eFile_Init());              //diskError("eFile_Init",0); 
  if(eFile_Format());            //diskError("eFile_Format",0); 
  eFile_Directory(&UART_OutChar);
  if(eFile_Create("file1"));     //diskError("eFile_Create",0);
  if(eFile_WOpen("file1"));      //diskError("eFile_WOpen",0);
  for(i=0;i<1000;i++){
    if(eFile_Write('a'+i%26))   //diskError("eFile_Write",i);
    if(i%52==51){
      if(eFile_Write('\n'));     //diskError("eFile_Write",i);  
      if(eFile_Write('\r'));     //diskError("eFile_Write",i);
    }
  }
  if(eFile_WClose());            //diskError("eFile_Close",0);
  eFile_Directory(&UART_OutChar);
  if(eFile_ROpen("file1"));      //diskError("eFile_ROpen",0);
  for(i=0;i<1000;i++){
    if(eFile_ReadNext(&data));   //diskError("eFile_ReadNext",i);
    UART_OutChar(data);
  }
  UART_OutChar(LF);
  UART_OutChar(CR);
  eFile_RClose();
  if(eFile_Delete("file1"));     //diskError("eFile_Delete",0);
  eFile_Directory(&UART_OutChar);
  bufLen = sprintf(testBuf,"Successful test of creating a file\n\r");
  UARTSend(testBuf, bufLen);

  OS_Kill();
}

int failure;
void testRedirect(void){
  int i,j;
  char t;
  eFile_Init();
  if(eFile_Format()) 
    failure = 1;
  eFile_RedirectToFile("testfile");

  for(i=0; i<50; i++){
	printLab(test2, 508);
  }

  eFile_EndRedirectToFile();

  eFile_ROpen("testfile");
  i=0;
  while(!eFile_ReadNext(&t)){
    UART_OutChar(t);
	if(i++ == 512){
	  j= OS_MsTime();
	  while(OS_MsTime()-j < 10){}
	  i = 0;
	}
  }

  eFile_RClose();
  OS_Kill();
}

//******************* test main2 **********
// SYSTICK interrupts, period established by OS_Launch
// Timer interrupts, period established by first call to OS_AddPeriodicThread
int testmain2(void){ 
  OS_Init();           // initialize, disable interrupts

//*******attach background tasks***********
  OS_AddPeriodicThread(&disk_timerproc,10*TIME_1MS,0);   // time out routines for disk
  
  NumCreated = 0 ;
// create initial foreground threads
  //NumCreated += OS_AddThread(&TestFile,128,1);
  NumCreated += OS_AddThread(&testRedirect,1024,1);  
  NumCreated += OS_AddThread(&IdleTask,128,3); 
 
  OS_Launch(10*TIME_1MS); // doesn't return, interrupts enabled in here
  return 0;               // this never executes
}

const BYTE test[] = "Here is some test data";
char fileName[] = "test";
BYTE test3 [1000];
int result, i;
char tChar;
// Test main
int main(void){
   int dummy;
//
//	Initialize port C
//
  SYSCTL_RCGC2_R |= SYSCTL_RCGC2_GPIOC;
  dummy = SYSCTL_RCGC2_R;
  dummy = SYSCTL_RCGC2_R;

  //	Set data direction out for PC7, PC5 and set to digital
  GPIO_PORTC_DIR_R |= 0xA0; 
  GPIO_PORTC_DEN_R |= 0xA0;
  
  GPIO_PORTC_DATA_R &= ~0x20;

  eFile_Init();
  eFile_Format();
  UART_Init();

  
  bufLen = sprintf(testBuf,"\n\rEE345M/EE380L, Lab 5 eFile test\n\r");
  UARTSend(testBuf, bufLen);

  eFile_Create(fileName);

  eFile_WOpen(fileName);

  

  i=0;
  do{
    eFile_Write(test2[i]);
  }while(test2[i++] != NULL);

  eFile_Write(test[0]);

  eFile_WClose();

  eFile_ROpen(fileName);

  i=0;
  while(!eFile_ReadNext(&tChar)){
	UART_OutChar(tChar);
  }

  eFile_RClose();

  eFile_Directory(&UART_OutChar);
  
  while(1){}

  return 0;
}

int outest2main(void){
  eFile_Init();
  eFile_Format();
  UART_Init();

  eFile_RedirectToFile("test");
 
  printLab(test2, 511);

  eFile_EndRedirectToFile();

  eFile_Directory(&UART_OutChar);

  eFile_ROpen("test");

  i=0;
  while(!eFile_ReadNext(&tChar)){
	UART_OutChar(tChar);
  }

  while(1){}
  
  return 0;
}

void printLab(unsigned char *pucBuffer, unsigned long ulCount){
   while(ulCount--)
    {
        // Write the next character to the software FIFO
        if(eFile_putc(*pucBuffer)){
		  eFile_EndRedirectToFile();
		  break;
		}
		pucBuffer++;
    }
}

